﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SoftwareConsulting.BI11.Studio.InternalServices;
using SoftwareConsulting.BI11.Studio.DataTransfer.Properties;
using SoftwareConsulting.BI11.Studio.BasicEntities;
using SoftwareConsulting.Interfaces.BasicEntities;
using SoftwareConsulting.BI11.Studio.Core.Project.Metadata;
using SoftwareConsulting.BI11.Studio.ProcessWait;

namespace SoftwareConsulting.BI11.Studio.DataTransfer
{
    /// <summary>
    /// Тип узла данных
    /// </summary>
    public enum DataNodeType
    {
        /// <summary>
        /// Не определен
        /// </summary>
        None = 0,
        /// <summary>
        /// Напрямую данные
        /// </summary>
        Directly = 1,
        /// <summary>
        /// Таблица BI-11
        /// </summary>
        Table = 2,
        /// <summary>
        /// Файл Microsoft Excel
        /// </summary>
        Excel = 3
    }

    /// <summary>
    /// Класс передатчика данных
    /// </summary>
    public class DataTransmitter
    {
        private DataNodeType _sourceDataType;//тип источника        
        private DataNodeType _destinationDataType;//тип приемника
        private DataNode _sourceDataNode;//узел источника данных
        private DataNode _destinationDataNode;//узел приемника данных

        /// <summary>
        /// Возвращает узел источника данных
        /// </summary>
        public object SourceDataNode
        {
            get
            {
                return _sourceDataNode;
            }
        }

        /// <summary>
        /// Устанавливает узел источника данных
        /// </summary>
        /// <param name="newDestinationDataNode"></param>
        public void SetSourceDataNode(DataNode newSourceDataNode)
        {
            switch(_sourceDataType)
            {
                case DataNodeType.Directly:
                    _sourceDataNode = newSourceDataNode as DirectDataNode;
                    break;
                case DataNodeType.Table:
                    _sourceDataNode = newSourceDataNode as TableDataNode;
                    break;
                case DataNodeType.Excel:
                    _sourceDataNode = newSourceDataNode as ExcelDataNode;
                    break;
                default:
                    Assert.Fail(Assert.Id.Assert00320);
                    break;
            }
        }

        /// <summary>
        /// Возвращает узел приемника данных
        /// </summary>
        public object DestinationDataNode
        {
            get
            {
                return _destinationDataNode;
            }
        }

        /// <summary>
        /// Устанавливает узел приемника данных
        /// </summary>
        /// <param name="newDestinationDataNode"></param>
        public void SetDestinationDataNode(DataNode newDestinationDataNode)
        {
            switch (_destinationDataType)
            {
                case DataNodeType.Directly:
                    _destinationDataNode = newDestinationDataNode as DirectDataNode;
                    break;
                case DataNodeType.Table:
                    _destinationDataNode = newDestinationDataNode as TableDataNode;
                    break;
                case DataNodeType.Excel:
                    _destinationDataNode = newDestinationDataNode as ExcelDataNode;
                    break;
                default:
                    Assert.Fail(Assert.Id.Assert00321);
                    break;
            }
        }

        /// <summary>
        /// Передает данные из источника в приемник
        /// </summary>
        /// <returns>true - успешно, false - не успешно или отменено</returns>
        /// <remarks>
        /// Реализованные на данный момент направления передачи:
        ///  напрямую -> таблица
        ///  напрямую -> напрямую
        ///  таблица -> напрямую
        ///  таблица -> таблица
        /// </remarks>
        public bool Transfer()
        {
            return Transfer(false);
        }

        /// <summary>
        /// Обрабатывает событие изменения прогресса работы источника
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void OnSourceProgress(object sender, ProgressEventArgs args)
        {            
            Processing.SetPercentOfPartByBorders(args.Progress, 0, 50);
        }

        /// <summary>
        /// Обрабатывает событие изменения прогресса работы приемника
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void OnDestinationProgress(object sender, ProgressEventArgs args)
        {
            Processing.SetPercentOfPartByBorders(args.Progress, 50, 100);
        }

        /// <summary>
        /// Передает данные из источника в приемник
        /// </summary>
        /// <returns>true - успешно, false - не успешно или отменено</returns>
        /// <remarks>
        /// Реализованные на данный момент направления передачи:
        ///  напрямую -> таблица
        ///  напрямую -> напрямую
        ///  таблица -> напрямую
        ///  таблица -> таблица
        /// </remarks>
        public bool Transfer(bool silent)
        {
            if ((_sourceDataNode == null) || !_sourceDataNode.IsReady)
                throw new BIDataNodeNotReadyException(null);
            if ((_destinationDataNode == null) || !_destinationDataNode.IsReady)
                throw new BIDataNodeNotReadyException(null);
            bool good = true;
            Processing.BeginWait();
            Processing.SetDescription(Resources.BI_TRANSFER_PROGRESS_SOURCE);
            Processing.ShowPercent(0);
            try
            {
                _sourceDataNode.OnProgress += OnSourceProgress;
                _destinationDataNode.OnProgress += OnDestinationProgress;                
                List<object[]> sourceData = new List<object[]>();
                switch (_sourceDataType)
                {
                    case DataNodeType.Directly:
                        sourceData = _sourceDataNode.GetData();
                        break;
                    case DataNodeType.Table:
                        (_sourceDataNode as TableDataNode).PullRecords();
                        sourceData = _sourceDataNode.GetData();
                        break;
                }
                Processing.SetDescription(Resources.BI_TRANSFER_PROGRESS_DESTINATION);
                _destinationDataNode.TransferData(sourceData);
            }
            finally
            {
                Processing.EndWait();
                _sourceDataNode.OnProgress -= OnSourceProgress;
                _destinationDataNode.OnProgress -= OnDestinationProgress;                
            }
            if (!silent)
            {
                GeneralMethods.ShowInformation(good ?
                    Resources.BI_TRANSFER_FINISHED_SUCCESS :
                    Resources.BI_TRANSFER_FINISHED_FAIL);
            }            
            return good;
        }

        /// <summary>
        /// Конструктор класса
        /// </summary>
        /// <param name="sourceDataType">тип источника</param>
        /// <param name="destinationDataType">тип приемника</param>
        public DataTransmitter(DataNodeType sourceDataType, DataNodeType destinationDataType)
        {
            _sourceDataType = sourceDataType;
            _destinationDataType = destinationDataType;
            _sourceDataNode = null;
            _destinationDataNode = null;
        }
    }
}
